Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pluginupdate.py: add support for adding/updating individual plugins #336137

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

PerchunPak
Copy link
Member

@PerchunPak PerchunPak commented Aug 20, 2024

Description of changes

This PRs adds long-awaited support for updating individual plugins to Vim and Kakoune (LuaEditor is a third class that uses pluginupdate.py, but they patch too much in pluginupdate, so I leave it to someone else).

As a bonus (though it was my main goal), I implemented adding an entry to generated.nix when adding a plugin using the script. I also implemented a whole bunch of bugfixes and I will document some things as comments here.

Feel free to correct grammar, I am not a native, so will gladly accept any grammar nitpicks.

Fixes #218584.

Things done

Things tested:

  • Vim
    • Full update (result file)
    • Individual update
    • Adding package adds an entry to generated.nix
  • Kakoune - seems broken on master, so leaving it on maintainer (@philiptaron)
  • Lua
    • Full update - ratelimits even with token and one worker, assuming works

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.11 Release Notes (or backporting 23.11 and 24.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

CC @teto (author of #218696), @figsoda (maintainer of Vim), @philiptaron (maintainer of Kakoune)


Add a 👍 reaction to pull requests you find important.

Returns:
True if we should update plugin and False if not.
"""
return plugin.name.replace(".", "-") in to_update
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can see how optimistic I was for this PR (26 lines of docs to one line of code)

@@ -559,6 +657,7 @@ def run(
parser = self.create_parser()
args = parser.parse_args()
command = args.command or "update"
logging.basicConfig()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this line, any logging using log variable didn't work. Also, why default log level is warning? It is not annoying on info level, should I change it too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging at info level is a good idea.

Comment on lines -385 to +386
log.debug("using plugin_line", plugin_line)
log.debug("using plugin_line %s", plugin_line)
pdesc = PluginDesc.load_from_string(fetch_config, plugin_line)
log.debug("loaded as pdesc", pdesc)
log.debug("loaded as pdesc %s", pdesc)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It raised an error where complained at the lack of %s

current: list[Tuple[PluginDesc, Plugin]],
fetched: List[Tuple[PluginDesc, Union[Exception, Plugin], Optional[Repo]]],
) -> List[Tuple[PluginDesc, Union[Exception, Plugin], Optional[Repo]]]:
result: Dict[str, Tuple[PluginDesc, Union[Exception, Plugin], Optional[Repo]]] = dict(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those types are copied from check_results func, and result of this function will be passed to it

# remove plugin from index file, so we won't add it
# to deprecations again
for i, plugin in enumerate(plugins):
if plugin.name == pdesc.name:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you could see at the description of third commit, someone just forgot about deleting plugins from index for years!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Time for some cleaning 🧹

@@ -772,7 +875,7 @@ def rewrite_input(
fieldnames = ["repo", "branch", "alias"]
writer = csv.DictWriter(f, fieldnames, dialect="unix", quoting=csv.QUOTE_NONE)
writer.writeheader()
for plugin in sorted(plugins):
for plugin in sorted(plugins, key=lambda x: x.name):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting fact: plugin's URI is not unique, but name is. It is because there can be multiple plugins in one repo but on different branches (e.g. different versions, see harpoon) and name is used as a key in the final result

sh = logging.StreamHandler()
formatter = logging.Formatter("%(name)s:%(levelname)s: %(message)s")
sh.setFormatter(formatter)
log.addHandler(sh)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary with logging.basicConf in the main file

@mweinelt
Copy link
Member

@ofborg eval

Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial feedback. This looks great -- thanks for your work here @PerchunPak.

What remains:

  1. I need to validate each URL update
  2. You mentioned that I have some work to do for kakoune. Could you make it more clear for me what's broken and what I ought to pay attention to?
  3. This deprecated.json thing is a total mess. What would cleanup look like?

Thank you!

outfile: str,
config: FetchConfig,
# TODO: implement support for adding/updating individual plugins
to_update: Optional[List[str]],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want to raise an error if this is non-None so that it's not frustrating that it's not working?

repo,
branch.strip(),
# alias is usually an empty string
# I wasted ~5 hours to find out this...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😢

Sometimes it's that way...


def get_current_plugins(self, nixpkgs) -> List[Plugin]:
def get_current_plugins(
self, config: FetchConfig, nixpkgs: str
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind pushing a commit that does ruff format on this file? Getting a consistent style would be great.

version = version_split[1] if len(version_split) > 1 else version_split[0]
date = datetime.strptime(version, "%Y-%m-%d")

pdesc = PluginDesc.load_from_string(config, attr["homePage"] + " as " + name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually do f strings instead of +, but it's only as preference.

Suggested change
pdesc = PluginDesc.load_from_string(config, attr["homePage"] + " as " + name)
pdesc = PluginDesc.load_from_string(config, f'{attr["homePage"]} as {name}')

def get_update(self, input_file: str, outfile: str, config: FetchConfig):
cache: Cache = Cache(self.get_current_plugins(self.nixpkgs), self.cache_file)
def filter_plugins_to_update(self, plugin: PluginDesc, to_update: List[str]) -> bool:
"""Function for filtering out plugins, that user doesn't want to update.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Function for filtering out plugins, that user doesn't want to update.
"""filter_plugins_to_update exists to filter out plugins that user doesn't want to update.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty sure this breaks the Google style I used in this docstring. Though the closest rule I could find is https://docs.astral.sh/ruff/rules/no-signature/

Comment on lines 487 to 514
filter_func = functools.partial(self.filter_plugins_to_update, to_update=to_update)
plugins_to_update = list(
filter(filter_func, current_plugin_specs)
if to_update
else current_plugin_specs
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm big on list comprehensions instead of functools.partial or map/filter calls, mostly because they seem to my eyes to read better.

What do you think about this suggestion?

Suggested change
filter_func = functools.partial(self.filter_plugins_to_update, to_update=to_update)
plugins_to_update = list(
filter(filter_func, current_plugin_specs)
if to_update
else current_plugin_specs
)
plugins_to_update = current_plugin_specs if len(to_update) == 0 else [
description
for description in current_plugin_specs
if self.filter_plugins_to_update(description, to_update)
)

@@ -559,6 +657,7 @@ def run(
parser = self.create_parser()
args = parser.parse_args()
command = args.command or "update"
logging.basicConfig()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging at info level is a good idea.

# remove plugin from index file, so we won't add it
# to deprecations again
for i, plugin in enumerate(plugins):
if plugin.name == pdesc.name:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Time for some cleaning 🧹

Comment on lines 904 to 907
args.input_file,
args.outfile,
fetch_config,
getattr(args, "update_only", None), # if script was called without arguments
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend using names for the parameters here.

Suggested change
args.input_file,
args.outfile,
fetch_config,
getattr(args, "update_only", None), # if script was called without arguments
input_file=args.input_file,
output_file=args.outfile,
config=fetch_config,
to_update=getattr(args, "update_only", None), # if script was called without arguments

@@ -21,30 +21,40 @@
)
import pluginupdate

GET_PLUGINS = f"""(with import <localpkgs> {{}};
GET_PLUGINS = f"""with import <localpkgs> {{ }};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the broken updater?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if you run

cd pkgs/applications/editors/kakoune/plugins
nix-shell update-shell.nix
python update.py

It outputs (on master and here is the same error)

error:
       … <borked>

         at «none»:0: (source not available)from call site

         at «string»:1:6:

            1| with import <localpkgs> { };
             |      ^
            2| let

       error: function 'anonymous lambda' called without required argument 'kakouneUtils'

       at /home/perchun/dev/nixpkgs/pkgs/applications/editors/kakoune/plugins/default.nix:1:1:

            1| { callPackage, config, kakouneUtils, lib }:
             | ^
            2|

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! It's on the list to go fix. I'm camping this weekend but will attend to it when back.

@PerchunPak PerchunPak force-pushed the updater-one-plugin branch 2 times, most recently from 03d3245 to 16419ba Compare August 21, 2024 08:36
@PerchunPak
Copy link
Member Author

PerchunPak commented Aug 21, 2024

Pushed changes from review and formatting changes in different force pushes for simpler reviewing. I didn't push it as a new commit, as it would create a lot of conflicts if there will be other changes.

Thanks for the review!

@PerchunPak
Copy link
Member Author

I need to validate each URL update

This should be easy with nixpkgs-review:

Result of nixpkgs-review pr 336137 run on x86_64-linux 1

3 packages built:
  • luarocks-packages-updater
  • nixpkgs-manual
  • vimPluginsUpdater

Which means no Vim plugins were changed/removed/added. I also quickly glanced over the diff on generated.nix after the full plugin update and didn't find any plugins that were moved/removed/added (before I created the PR there were a few bugs with sorting).

This deprecated.json thing is a total mess. What would cleanup look like?

What do you mean? The file deprecated.json or the code for it? If the code, it is in a good state compared to other parts of the code I've seen in this file.

:param expr nix expression to fetch current plugins
:param nixpkgs Path towards a nixpkgs checkout
'''
"""
Copy link
Member

@teto teto Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aws this changed by the black formatter ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran ruff format which is 99.9% compatible with black (just because it was installed on my system), so whatever?

If you want to update only certain plugins, you can specify their names to `--update` flag. Note that those name must be the same as in `pkgs/applications/editors/vim/plugins/vim-plugin-names` file.

```sh
nix-shell -p vimPluginsUpdater --run 'vim-plugins-updater --update "nvim-treesitter" "LazyVim"'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apparently it's not --update but update:

nix run .#vimPluginsUpdater --  update nvim-treesitter LazyVim
WARNING:root:You have enabled parallel updates but haven't set a github token.
You may be hit with `HTTP Error 429: too many requests` as a consequence.Either set --proc=1 or --github-token=YOUR_TOKEN. 
path is '/nix/store/rgwip825v0m4nhsvqyabf0mb2as81x0q-0b8b78f9d08dc338a146eb4cd4bcbed8dd36a783.tar.gz'
2 of 1471 were checked

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here, thanks!

@teto
Copy link
Member

teto commented Aug 21, 2024

thanks for the great work. It's a very exciting feature. I had thought of a treesitter-based solution but this seems to work as well. Not having the feature in all updaters is no problem, that's part of the design.

I am a bit annoyed that you have mixed different things in the PR (logging level, formatting, sorting, new feature). Most of it I want to merge but some of it (the update filtering) I would like to test & experiment with myself more. Would it be too much to ask for the sorting fix in a separate PR ?
For the logging part, the approach is to print user-facing messages and logging is a separate thing, which is why the level is set to WARN (since the logger is verbose, which is ok, it's targeted at developers first).
As for the formatting, it's supposed to be "black"-ified but maybe some parts were not done correctly.
If you could open separate PRs for the different changes, it would help with review work.

@PerchunPak
Copy link
Member Author

I am a bit annoyed that you have mixed different things in the PR (logging level, formatting, sorting, new feature). ... Would it be too much to ask for the sorting fix in a separate PR ?

Unfortunately, most of those changes are QOL and usually they fix some weird bug, that prevents from properly implementing individual updates. For example, before sorting was completely broken (it sorted by PluginDesc.name, PluginDesc.name implementation was:

if self.alias is not None:
    return self.alias
else:
    return self.repo.name

BUT self.alias, if unset, was an empty string (because in CSV if something is unset, it is an empty string), instead of None, so it sorted by what request finished first, instead of proper name). This resulted in vim-updater-script add ... resorts half a file, if ran right after vim-updater-script update. Implementing proper sorting prevents merge conflicts. And I don't see much sense in individual updates, if those generate huge diffs that are hard to review.

For the logging part, the approach is to print user-facing messages and logging is a separate thing, which is why the level is set to WARN (since the logger is verbose, which is ok, it's targeted at developers first).

Ok, I will revert INFO by default.

@PerchunPak PerchunPak force-pushed the updater-one-plugin branch 3 times, most recently from 9b7f93d to 644404a Compare August 22, 2024 12:07
@PerchunPak
Copy link
Member Author

I am reviewing (and merging with the help of GaetanLepage) all vimPlugins.* PRs, so conflicts here are probably to stay until merge (they are not worth solving, if next merged PR will break them again + I will need to ensure sorting is correct right before merge)

@PerchunPak
Copy link
Member Author

Fixed merge conflicts, also removed 644404a as it was merged in #341146

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

improve vim plugin updater: per-plugin update (+ add it as a flake.nix application ?)
5 participants